package com.finchina.myview.RoundImage;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.Xfermode;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;

import com.finchina.myview.R;

import java.lang.ref.WeakReference;

/**
 * 作者：黄赛赛 on 2015/9/17 16:03
 *http://doc.okbase.net/JczmDeveloper/archive/121153.html
 * 本文使用Xfermode模式中的DST_IN模式来实现要达到的效果，当然大家也可以采用其他的模式，比如SRC_IN等都可以实现该效果。
 *Xfermode渲染模式简介：
 xfermode影响在Canvas已经有的图像上绘制新的颜色的方式
 * 正常的情况下,在图像上绘制新的形状,如果新的Paint不是透明的,那么会遮挡下面的颜色.
 * 如果新的Paint是透明的,那么会被染成下面的颜色

 下面的Xfermode子类可以改变这种行为：

 AvoidXfermode  指定了一个颜色和容差，强制Paint避免在它上面绘图(或者只在它上面绘图)。

 PixelXorXfermode  当覆盖已有的颜色时，应用一个简单的像素XOR操作。

 PorterDuffXfermode  这是一个非常强大的转换模式，使用它，可以使用图像合成的16条Porter-Duff规则的任意一条来控制Paint如何与已有的Canvas图像进行交互。
 这里不得不提到那个经典的图：
 从上面我们可以看到PorterDuff.Mode为枚举类,一共有16个枚举值:
 1.PorterDuff.Mode.CLEAR
 所绘制不会提交到画布上。
 2.PorterDuff.Mode.SRC
 显示上层绘制图片
 3.PorterDuff.Mode.DST
 显示下层绘制图片
 4.PorterDuff.Mode.SRC_OVER
 正常绘制显示，上下层绘制叠盖。
 5.PorterDuff.Mode.DST_OVER
 上下层都显示。下层居上显示。
 6.PorterDuff.Mode.SRC_IN
 取两层绘制交集。显示上层。
 7.PorterDuff.Mode.DST_IN
 取两层绘制交集。显示下层。
 8.PorterDuff.Mode.SRC_OUT
 取上层绘制非交集部分。
 9.PorterDuff.Mode.DST_OUT
 取下层绘制非交集部分。
 10.PorterDuff.Mode.SRC_ATOP
 取下层非交集部分与上层交集部分
 11.PorterDuff.Mode.DST_ATOP
 取上层非交集部分与下层交集部分
 12.PorterDuff.Mode.XOR
 异或：去除两图层交集部分
 13.PorterDuff.Mode.DARKEN
 取两图层全部区域，交集部分颜色加深
 14.PorterDuff.Mode.LIGHTEN
 取两图层全部，点亮交集部分颜色
 15.PorterDuff.Mode.MULTIPLY
 取两图层交集部分叠加后颜色
 16.PorterDuff.Mode.SCREEN
 取两图层全部区域，交集部分变为透明色
 * @version V1.0
 * @Description: ${todo}()
 */
public class RoundImageViewByXfermode extends ImageView {
    private Paint mPaint;
    private Xfermode mXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
    private Bitmap mMaskBitmap;

    private WeakReference<Bitmap> mWeakBitmap;

    /**
     * 图片的类型，圆形or圆角
     */
    private int type;
    public static final int TYPE_CIRCLE = 0;
    public static final int TYPE_ROUND = 1;
    public static final int TYPE_OVAL = 2;
    /**
     * 圆角大小的默认值
     */
    private static final int BODER_RADIUS_DEFAULT = 20;
    /**
     * 圆角的大小
     */
    private int mBorderRadius;



    public RoundImageViewByXfermode(Context context) {
        this(context, null);
    }

    public RoundImageViewByXfermode(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RoundImageViewByXfermode(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);


        TypedArray ta = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.RoundImageViewByXfermode, defStyleAttr, 0 );
        mBorderRadius = ta.getDimensionPixelOffset(R.styleable.RoundImageViewByXfermode_rivbx_boardwidth, BODER_RADIUS_DEFAULT);
        type = ta.getInt(R.styleable.RoundImageViewByXfermode_rivbx_type, TYPE_CIRCLE );
        ta.recycle();

        mPaint = new Paint();
        mPaint.setAntiAlias(true);

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (type == TYPE_CIRCLE){
            int width = Math.min(getMeasuredWidth(), getMeasuredHeight());
            setMeasuredDimension(width, width);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
//        super.onDraw(canvas);
        Bitmap bmp = mWeakBitmap == null ? null : mWeakBitmap.get();
        if (bmp != null){
            mPaint.setXfermode(null);
            canvas.drawBitmap(bmp, 0,0, mPaint);
        }else {
            //拿到Drawable
            Drawable drawable = getDrawable();

            if (drawable != null){
                //获取drawable的宽和高
                int dWidth = drawable.getIntrinsicWidth();
                int dHeight = drawable.getIntrinsicHeight();
                //创建bitmap
                bmp = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
                float scale = 1.0f;
                //创建画布
                Canvas drawableCanvas = new Canvas(bmp);
                //按照bitmap的宽高，以及view的宽高，计算缩放比例；因为设置的src宽高比例可能和imageview的宽高比例不同，这里我们不希望图片失真；
                if (type == TYPE_ROUND)
                {
                    // 如果图片的宽或者高与view的宽高不匹配，计算出需要缩放的比例；缩放后的图片的宽高，一定要大于我们view的宽高；所以我们这里取大值；
                    scale = Math.max(getWidth() * 1.0f / dWidth, getHeight()
                            * 1.0f / dHeight);
                } else
                {
                    scale = getWidth() * 1.0F / Math.min(dWidth, dHeight);
                    //根据缩放比例，设置bounds，相当于缩放图片了
                    drawable.setBounds(0,0, (int)(dWidth *scale), (int)(dHeight *scale));
                    drawable.draw(drawableCanvas);
                    if (mMaskBitmap == null || mMaskBitmap.isRecycled())
                    {
                        mMaskBitmap = getBitmap();
                    }
                    // Draw Bitmap.
                    //为paint设置Xfermode 渲染模式
                    mPaint.reset();
                    mPaint.setFilterBitmap(false);
                    mPaint.setXfermode(mXfermode);
                    //绘制形状
                    drawableCanvas.drawBitmap(mMaskBitmap, 0,0, mPaint);
                    mPaint.setXfermode(null);
                    //将准备好的bitmap绘制出来
                    canvas.drawBitmap(bmp,0,0,null);
                    //bitmap缓存起来，避免每次调用onDraw，分配内存
                    mWeakBitmap = new WeakReference<Bitmap>(bmp);
                }
            }
        }
    }

    @Override
    public void invalidate() {
        mWeakBitmap = null;
        if (mMaskBitmap !=null && !mMaskBitmap.isRecycled()){
            mMaskBitmap.recycle();
            mMaskBitmap = null;
        }
        super.invalidate();
    }

    /**
     * 绘制形状
     * @return
     */
    public Bitmap getBitmap(){
        Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(),
                Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.BLACK);
        if (type == TYPE_CIRCLE){
            canvas.drawCircle(getWidth()/2, getWidth()/2, getWidth()/2, paint);
        }else if (type == TYPE_ROUND) {
            canvas.drawRoundRect(new RectF(0, 0, getWidth(), getHeight()), mBorderRadius, mBorderRadius, paint);
        }else if (type == TYPE_ROUND) {
            //绘制椭圆
            canvas.drawOval(new RectF(0, 0, getWidth(), getHeight()), mPaint);
        }
        return bitmap;
    }

    /**
     * 根据原图和变长绘制圆形图片
     *
     * @param source
     * @param min
     * @return
     */
    private Bitmap createCircleImage(Bitmap source, int min)
    {
        final Paint paint = new Paint();
        paint.setAntiAlias(true);
        Bitmap target = Bitmap.createBitmap(min, min, Bitmap.Config.ARGB_8888);
        /**
         * 产生一个同样大小的画布
         */
        Canvas canvas = new Canvas(target);
        /**
         * 首先绘制圆形
         */
        canvas.drawCircle(min / 2, min / 2, min / 2, paint);
        /**
         * 使用SRC_IN
         */
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        /**
         * 绘制图片
         */
        canvas.drawBitmap(source, 0, 0, paint);
        return target;
    }

    /**
     * 根据原图添加圆角
     *
     * @param source
     * @return
     */
   /* private Bitmap createRoundConerImage(Bitmap source)
    {
        final Paint paint = new Paint();
        paint.setAntiAlias(true);
        Bitmap target = Bitmap.createBitmap(mWidth, mHeight, Config.ARGB_8888);
        Canvas canvas = new Canvas(target);
        RectF rect = new RectF(0, 0, source.getWidth(), source.getHeight());
        canvas.drawRoundRect(rect, mRadius, mRadius, paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(source, 0, 0, paint);
        return target;
    }*/

}

 /*
 http://blog.csdn.net/t12x3456/article/details/10432935
 Android 颜色渲染(九)  PorterDuff及Xfermode详解
之前已经讲过了除ComposeShader之外Shader的全部子类, 在讲ComposeShader(组合渲染)之前,  由于构造ComposeShader需要 PorterDuffXfermode或者PorterDuff.Mode作为参数,所以在此先详细地了解下这两个类的作用,这对之后的绘图会有很大的帮助:
        在讲具体的使用之前补充一点知识,这就是 ProterDuff的由来:
        相信大多数人看到这个ProterDuff单词很奇怪了吧，这肿么个意思呢,然后就用有道啊，金山啊开始翻译，但是翻译软件给出的结果肯定还是  ProterDuff或者"未找到".
        这是神马情况呢？因为ProterDuff是两个人名的组合: Tomas Proter和 Tom Duff. 他们是最早在SIGGRAPH上提出图形混合概念的大神级人物.有兴趣的童靴们可以自己查下并深入了解，在此不再做过多描述.

        利用ProterBuff.Mode我们可以完成任意2D图像测操作， 比如涂鸦画板应用中的橡皮擦效果，绘制各种自定义的进度,等等很强大的效果，下面请看具体的介绍:

        Xfermode有三个子类 :
        AvoidXfermode  指定了一个颜色和容差，强制Paint避免在它上面绘图(或者只在它上面绘图)。
        PixelXorXfermode  当覆盖已有的颜色时，应用一个简单的像素异或操作。
        PorterDuffXfermode  这是一个非常强大的转换模式，使用它，可以使用图像合成的16条Porter-Duff规则的任意一条来控制Paint如何与已有的Canvas图像进行交互。
        要应用转换模式，可以使用setXferMode方法，如下所示：

        AvoidXfermode avoid = new AvoidXfermode(Color.BLUE, 10, AvoidXfermode.Mode. AVOID);
        borderPen.setXfermode(avoid);*/
